<template>
    <div class="datacenter-3d-container">
        <canvas ref="canvasRef" class="datacenter-3d-canvas"></canvas>
    </div>
</template>

<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, computed } from 'vue'
import * as THREE from 'three'
import { useDataCenterStore } from '@/stores/datacenter'
import { CabinetMeshFactory, RowMeshFactory } from '@/three'

// Props and Emits
const emit = defineEmits<{
    'cabinet-selected': [cabinetId: string | null]
    'device-selected': [deviceId: string | null, cabinetId: string | null]
}>()

// Template refs
const canvasRef = ref<HTMLCanvasElement>()

// Store
const dataCenterStore = useDataCenterStore()

// Three.js objects
let scene: THREE.Scene
let camera: THREE.PerspectiveCamera
let renderer: THREE.WebGLRenderer
let animationId: number
let mouseX = 0
let mouseY = 0
let targetRotationX = 0
let targetRotationY = 0

// 射线投射相关
let raycaster: THREE.Raycaster
let mouse: THREE.Vector2

// 摄像机控制
let cameraDistance = 15000 // 固定摄像机距离 15m

// Component state
// Mouse interaction variables
let isMouseDown = false
let mouseXOnMouseDown = 0
let mouseYOnMouseDown = 0
let targetRotationOnMouseDownX = 0
let targetRotationOnMouseDownY = 0

// 3D object references
const rowMeshes = new Map<string, THREE.Group>()
const cabinetMeshes = new Map<string, THREE.Group>()

// 选中状态
let selectedCabinetMesh: THREE.Group | null = null
let selectedDeviceMesh: THREE.Mesh | null = null
let originalMaterials: THREE.Material[] = []

// 监听设备变化 - 深度监听所有机柜的设备
const allCabinetsDevicesSignature = computed(() => {
    return dataCenterStore.rows.flatMap(row =>
        row.cabinets.map(cabinet => ({
            cabinetId: cabinet.id,
            deviceCount: cabinet.devices.length,
            devices: cabinet.devices.map(device => ({
                id: device.id,
                rackPosition: device.rackPosition,
                rackUnits: device.rackUnits,
                type: device.type
            }))
        }))
    )
})

const initThreeJS = () => {
    if (!canvasRef.value) return

    // Scene setup
    scene = new THREE.Scene()
    scene.background = new THREE.Color(0x2a2a2a)

    // Camera setup
    camera = new THREE.PerspectiveCamera(
        75,
        canvasRef.value.clientWidth / canvasRef.value.clientHeight,
        1, // 近裁剪面 1mm
        100000 // 远裁剪面 100m = 100000mm
    )

    // 设置初始摄像机位置和旋转角度
    targetRotationX = 0.785  // 45度
    targetRotationY = 0.3    // 约17度仰角
    camera.position.x = Math.cos(targetRotationX) * Math.cos(targetRotationY) * cameraDistance
    camera.position.z = Math.sin(targetRotationX) * Math.cos(targetRotationY) * cameraDistance
    camera.position.y = Math.sin(targetRotationY) * cameraDistance
    camera.lookAt(0, 0, 0)

    // Renderer setup
    renderer = new THREE.WebGLRenderer({
        canvas: canvasRef.value,
        antialias: true
    })
    renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
    renderer.shadowMap.enabled = true
    renderer.shadowMap.type = THREE.PCFSoftShadowMap

    // 初始化射线投射器
    raycaster = new THREE.Raycaster()
    mouse = new THREE.Vector2()

    // Add lighting
    const ambientLight = new THREE.AmbientLight(0x404040, 0.4)
    scene.add(ambientLight)

    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
    directionalLight.position.set(20000, 20000, 20000) // 20m
    directionalLight.castShadow = true
    directionalLight.shadow.mapSize.width = 2048
    directionalLight.shadow.mapSize.height = 2048
    directionalLight.shadow.camera.near = 100
    directionalLight.shadow.camera.far = 100000
    directionalLight.shadow.camera.left = -20000
    directionalLight.shadow.camera.right = 20000
    directionalLight.shadow.camera.top = 20000
    directionalLight.shadow.camera.bottom = -20000
    scene.add(directionalLight)

    // Add grid helper (20m x 20m, 1m intervals)
    const gridHelper = new THREE.GridHelper(20000, 20, 0x444444, 0x444444)
    scene.add(gridHelper)

    // Add axis helper (5m length)
    const axesHelper = new THREE.AxesHelper(5000)
    scene.add(axesHelper)

    // Add mouse event listeners
    addEventListeners()

    // Load existing elements
    renderDataCenterElements()

    // Start animation loop
    animate()
}

const renderDataCenterElements = () => {
    // Clear existing meshes
    clearAllMeshes()

    // Render rows and their cabinets
    dataCenterStore.rows.forEach(row => {
        createRowMesh(row)
    })
}

const createRowMesh = (row: any) => {
    // 使用RowMeshFactory创建行指示器
    const rowGroup = RowMeshFactory.create(row)

    // 添加机柜
    row.cabinets.forEach((cabinet: any) => {
        const cabinetMesh = createCabinetMeshObject(cabinet, row)
        rowGroup.add(cabinetMesh)
        cabinetMeshes.set(cabinet.id, cabinetMesh)
    })

    scene.add(rowGroup)
    rowMeshes.set(row.id, rowGroup)
}

const createCabinetMeshObject = (cabinet: any, row: any) => {
    // 使用CabinetMeshFactory创建机柜
    const cabinetGroup = CabinetMeshFactory.create(cabinet)

    // 添加userData用于识别机柜
    cabinetGroup.userData = {
        cabinetId: cabinet.id,
        rowId: row.id,
        type: 'cabinet'
    }

    // 使用Row的calculateCabinetPosition方法获取正确的3D坐标
    const actualPosition = row.calculateCabinetPosition(cabinet.position)

    cabinetGroup.position.set(
        actualPosition.x,
        actualPosition.y + cabinet.height / 2, // 底部定位调整
        actualPosition.z
    )

    return cabinetGroup
}

const clearAllMeshes = () => {
    // Remove rows and their cabinets
    rowMeshes.forEach(group => {
        scene.remove(group)
        // Dispose of geometries and materials
        group.traverse((child) => {
            if (child instanceof THREE.Mesh) {
                if (child.geometry) child.geometry.dispose()
                if (Array.isArray(child.material)) {
                    child.material.forEach(material => material.dispose())
                } else if (child.material) {
                    child.material.dispose()
                }
            }
            if (child instanceof THREE.Line) {
                if (child.geometry) child.geometry.dispose()
                if (child.material) child.material.dispose()
            }
        })
    })
    rowMeshes.clear()
    cabinetMeshes.clear()
    selectedCabinetMesh = null
    selectedDeviceMesh = null
    originalMaterials = []
}

// 监听数据中心元素变化
watch(() => dataCenterStore.rows, () => {
    if (scene) {
        renderDataCenterElements()
    }
}, { deep: true })

// 监听设备变化
watch(allCabinetsDevicesSignature, () => {
    if (scene) {
        renderDataCenterElements()
    }
}, { deep: true })

const addEventListeners = () => {
    if (!canvasRef.value) return

    canvasRef.value.addEventListener('mousedown', onMouseDown)
    canvasRef.value.addEventListener('mousemove', onMouseMove)
    canvasRef.value.addEventListener('mouseup', onMouseUp)
    canvasRef.value.addEventListener('click', handleCanvasClick)
    canvasRef.value.addEventListener('wheel', onWheel)
    window.addEventListener('resize', onWindowResize)
}

const removeEventListeners = () => {
    if (!canvasRef.value) return

    canvasRef.value.removeEventListener('mousedown', onMouseDown)
    canvasRef.value.removeEventListener('mousemove', onMouseMove)
    canvasRef.value.removeEventListener('mouseup', onMouseUp)
    canvasRef.value.removeEventListener('click', handleCanvasClick)
    canvasRef.value.removeEventListener('wheel', onWheel)
    window.removeEventListener('resize', onWindowResize)
}

const onMouseDown = (event: MouseEvent) => {
    event.preventDefault()
    isMouseDown = true
    mouseXOnMouseDown = event.clientX - window.innerWidth / 2
    mouseYOnMouseDown = event.clientY - window.innerHeight / 2
    targetRotationOnMouseDownX = targetRotationX
    targetRotationOnMouseDownY = targetRotationY
}

const onMouseMove = (event: MouseEvent) => {
    if (!isMouseDown) return

    mouseX = event.clientX - window.innerWidth / 2
    mouseY = event.clientY - window.innerHeight / 2

    targetRotationX = targetRotationOnMouseDownX + (mouseX - mouseXOnMouseDown) * 0.02
    targetRotationY = targetRotationOnMouseDownY + (mouseY - mouseYOnMouseDown) * 0.02
}

const onMouseUp = () => {
    isMouseDown = false
}

const onWheel = (event: WheelEvent) => {
    event.preventDefault()
    const zoomSpeed = 0.1
    const direction = event.deltaY > 0 ? 1 : -1

    cameraDistance *= (1 + direction * zoomSpeed)
    cameraDistance = Math.max(2000, Math.min(50000, cameraDistance)) // 限制在 2m 到 50m
}

const onWindowResize = () => {
    if (!canvasRef.value || !camera || !renderer) return

    camera.aspect = canvasRef.value.clientWidth / canvasRef.value.clientHeight
    camera.updateProjectionMatrix()
    renderer.setSize(canvasRef.value.clientWidth, canvasRef.value.clientHeight)
}

const animate = () => {
    animationId = requestAnimationFrame(animate)

    // 直接设置摄像机位置，无惯性，保持距离恒定
    camera.position.x = Math.cos(targetRotationX) * Math.cos(targetRotationY) * cameraDistance
    camera.position.z = Math.sin(targetRotationX) * Math.cos(targetRotationY) * cameraDistance
    camera.position.y = Math.sin(targetRotationY) * cameraDistance

    camera.lookAt(0, 0, 0)

    renderer.render(scene, camera)
}

// 机柜选择功能
const selectCabinet = (cabinetGroup: THREE.Group | null) => {
    // 先清除之前的选中状态
    clearSelection()

    selectedCabinetMesh = cabinetGroup

    if (cabinetGroup) {
        // 保存原始材质并应用高亮效果
        cabinetGroup.traverse((child) => {
            if (child instanceof THREE.Mesh) {
                if (Array.isArray(child.material)) {
                    child.material.forEach(mat => originalMaterials.push(mat.clone()))
                } else {
                    originalMaterials.push(child.material.clone())
                }

                // 创建高亮材质
                const highlightMaterial = new THREE.MeshLambertMaterial({
                    color: 0x00ff00,
                    transparent: true,
                    opacity: 0.8
                })
                child.material = highlightMaterial
            }
        })

        // 发送选中事件
        emit('cabinet-selected', cabinetGroup.userData.cabinetId)
        emit('device-selected', null, null)
    } else {
        emit('cabinet-selected', null)
        emit('device-selected', null, null)
    }
}

// 设备选择功能
const selectDevice = (deviceMesh: THREE.Mesh | null) => {
    // 先清除之前的选中状态
    clearSelection()

    selectedDeviceMesh = deviceMesh

    if (deviceMesh) {
        // 保存原始材质
        if (Array.isArray(deviceMesh.material)) {
            deviceMesh.material.forEach(mat => originalMaterials.push(mat.clone()))
        } else {
            originalMaterials.push(deviceMesh.material.clone())
        }

        // 创建设备高亮材质
        const highlightMaterial = new THREE.MeshLambertMaterial({
            color: 0xffff00, // 黄色高亮
            transparent: true,
            opacity: 0.9,
            emissive: 0x333300,
            emissiveIntensity: 0.3
        })
        deviceMesh.material = highlightMaterial

        // 发送选中事件
        emit('device-selected', deviceMesh.userData.deviceId, deviceMesh.userData.cabinetId)
        emit('cabinet-selected', null)
    } else {
        emit('device-selected', null, null)
        emit('cabinet-selected', null)
    }
}

// 清除选中状态
const clearSelection = () => {
    // 恢复机柜材质
    if (selectedCabinetMesh && originalMaterials.length > 0) {
        let materialIndex = 0
        selectedCabinetMesh.traverse((child) => {
            if (child instanceof THREE.Mesh && materialIndex < originalMaterials.length) {
                child.material = originalMaterials[materialIndex]
                materialIndex++
            }
        })
    }

    // 恢复设备材质
    if (selectedDeviceMesh && originalMaterials.length > 0) {
        if (Array.isArray(selectedDeviceMesh.material)) {
            selectedDeviceMesh.material = originalMaterials[0]
        } else {
            selectedDeviceMesh.material = originalMaterials[0]
        }
    }

    selectedCabinetMesh = null
    selectedDeviceMesh = null
    originalMaterials = []
}

// 处理点击事件
const handleCanvasClick = (event: MouseEvent) => {
    // 只在非拖拽情况下处理点击
    if (isMouseDown) return

    if (!canvasRef.value) return

    // 计算鼠标位置
    const rect = canvasRef.value.getBoundingClientRect()
    mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1
    mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1

    // 射线投射
    raycaster.setFromCamera(mouse, camera)

    // 获取所有可点击对象（设备和机柜）
    const clickableObjects: THREE.Object3D[] = []
    cabinetMeshes.forEach(group => {
        group.traverse((child) => {
            if (child instanceof THREE.Mesh) {
                clickableObjects.push(child)
            }
        })
    })

    const intersects = raycaster.intersectObjects(clickableObjects)

    if (intersects.length > 0) {
        const clickedObject = intersects[0].object

        // 检查是否点击的是设备
        if (clickedObject.userData && clickedObject.userData.type === 'device') {
            selectDevice(clickedObject as THREE.Mesh)
            return
        }

        // 检查是否点击的是机柜
        let targetCabinet: THREE.Group | null = null
        let current = clickedObject

        while (current.parent && !targetCabinet) {
            if (current.userData && current.userData.type === 'cabinet') {
                targetCabinet = current as THREE.Group
                break
            }
            current = current.parent
        }

        if (targetCabinet) {
            selectCabinet(targetCabinet)
        } else {
            selectCabinet(null)
            selectDevice(null)
        }
    } else {
        selectCabinet(null)
        selectDevice(null)
    }
}

onMounted(() => {
    initThreeJS()
})

onUnmounted(() => {
    if (animationId) {
        cancelAnimationFrame(animationId)
    }
    removeEventListeners()
    clearAllMeshes()
    if (renderer) {
        renderer.dispose()
    }
})
</script>

<style scoped>
.datacenter-3d-container {
    position: relative;
    width: 100%;
    height: 100vh;
    background: #000;
}

.datacenter-3d-canvas {
    width: 100%;
    height: 100%;
    display: block;
    cursor: grab;
}

.datacenter-3d-canvas:active {
    cursor: grabbing;
}
</style>